package effectiveJava.Serializable;

import lombok.Data;
import lombok.ToString;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
 * Created by dongyuncong on 2017/8/28.
 */
@Data
@ToString
public class SerializableEntity implements Serializable {

    private static final long serialVersionUID = 1L;

    private String name;
    // TODO: 2017/8/28 当一个对象的实例变量引用其他对象，序列化该对象时也把引用对象进行序列化  (前提是引用对象也实现了序列化)
    private Apple apple;

    private transient int data;

    private transient long activationTime;

    /**
     * 方法writeObject处理对象的序列化。如果声明该方法，它将会被ObjectOutputStream调用而不是默认的序列化进程。如果你是第一次看见它，你会很惊奇尽管它们被外部类调用但事实上这是两个private的方法。并且它们既不存在于java.lang.Object，也没有在Serializable中声明。那么ObjectOutputStream如何使用它们的呢？
     * todo 这个嘛，ObjectOutputStream使用了反射来寻找是否声明了这两个方法。因为ObjectOutputStream使用getPrivateMethod，所以这些方法不得不被声明为priate以至于供ObjectOutputStream来使用。
     * <p>
     * 在两个方法的开始处，你会发现调用了defaultWriteObject()和defaultReadObject()。它们做的是默认的序列化进程，就像写/读所有的non-transient和 non-static字段(但他们不会去做serialVersionUID的检查).
     * todo 通常说来，所有我们想要自己处理的字段都应该声明为transient。这样的话，defaultWriteObject/defaultReadObject便可以专注于其余字段，而我们则可为这些特定的字段(译者：指transient)定制序列化。
     *
     * @param oos
     * @throws IOException
     */
    private void writeObject(ObjectOutputStream oos) throws IOException {
        oos.defaultWriteObject();
        oos.writeInt(data);
        oos.writeLong(activationTime);
        System.out.println("session serialized");
    }

    private void readObject(ObjectInputStream ois) throws IOException,
            ClassNotFoundException {
        ois.defaultReadObject();
        /*todo Write的顺序和read的顺序需要对应，譬如有多个字段都用wirteInt一一写入流中，那么readInt需要按照顺序将其赋值*/
        data = ois.readInt();
        activationTime = ois.readLong();
        System.out.println("session deserialized");
    }
}
